package hydrap2p.download.strategy;

import hydrap2p.download.DownloaderImpl;
import hydrap2p.download.ProtocolAdapter;
import hydrap2p.download.Source;
import hydrap2p.helper.ServiceConnector;
import hydrap2p.library.Range;
import hydrap2p.logging.Level;
import hydrap2p.logging.Logging;
import hydrap2p.logging.LoggingImpl;

import org.apache.thrift.TException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.Marker;
import org.slf4j.MarkerFactory;

/**
 * Torrent downloads will have a single BitTorrent source which basically acts as a marker and contains all the relevant torrent info.
 * The Downloader will branch on the source protocol and send it 
 * 
 * @author Phil
 *
 */
public class BTStrategy implements DownloadStrategy {
	// Init logger
	static {
		LoggingImpl.configureLog4J();
	}
	
	// Class string name, doubling as logging marker
	private static final Marker TAG = MarkerFactory.getDetachedMarker("BTStrategy");

	// Console logger - used before connections established
	private static final Logger consoleLogger = LoggerFactory.getLogger(TAG.getName());
	
	/* (non-Javadoc)
	 * @see hydrap2p.download.strategy.DownloadStrategy#downloadNextChunk(hydrap2p.download.DownloaderImpl, long, hydrap2p.download.Source)
	 */
	@Override
	public void downloadNextChunk(final DownloaderImpl downloader, final long uid, final Source source) throws TException {
		final ProtocolAdapter p = downloader.getProtocolByType("bittorrent");
		final Range finalRange = null;
			
		if(p != null) {
			Thread t = new Thread(new Runnable() {
				@Override
				public void run() {
					try {
						p.download(uid, source, finalRange);
					} catch(TException e) {
						log(Level.ERROR, "TException thrown by download call!");
						e.printStackTrace();
					}
				}
			});
			
			t.start();
		}
		else {
			log(Level.ERROR, "Failed to contact protocol: " + "bittorrent");
		}
	}
	
	/**
	 * Log.
	 * 
	 * @param severity the severity
	 * @param logMessage the log message
	 */
	public void log(Level severity, String logMessage) {
		Logging.Client logging = ServiceConnector.getLogger();
		
		//Log to Logging module if possible, and fall back to console.
		try {
			logging.log(severity, TAG.toString(), logMessage);
		} catch(TException e) {
			logToSystemError(severity, logMessage);
		} catch(NullPointerException e) {
			logToSystemError(severity, logMessage);
		}
	}
	
	/**
	 * Log to system error.
	 * 
	 * @param severity the severity
	 * @param logMessage the log message
	 */
	private void logToSystemError(Level severity, String logMessage) {
		//Log to system error.  If they can't be arsed to use a Logging constant as severity, the message gets logged at trace level
		switch(severity) {
		case VERBOSE:
			consoleLogger.trace(TAG, logMessage);
			break;
		case DEBUG:
			consoleLogger.debug(TAG, logMessage);
			break;
		case INFO:
			consoleLogger.info(TAG, logMessage);
			break;
		case MISHAP:
			consoleLogger.warn(TAG, logMessage);
			break;
		case ERROR:
			consoleLogger.error(TAG, logMessage);
			break;
		default:
			consoleLogger.trace(TAG, logMessage);
		}
	}
}
